#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/un.h> 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <ctype.h>


#include "constantes.h"
#include "estructuras.h"
#include "configuracion.h"
#include "sockets.h"
#include "algoritmo.h"
#include "estadisticas.h"
#include "commands.h"
#include "NIPC.h"
#include "consola.h"

int numoletra(char letra);
void intacad ( int n , char* cadena);
char* Generar_Desc_ID ( void );
extern ListConfig * listaConfig;
int Sock_consola;
int ALG;

int main(){
	
    char *buffer;		
    int i, respuesta, iEnv;
    int len;
    struct sockaddr_un remote;
	char* cadena;
	char input[100];
	char sSocket[20];

	
		
	printf("\nCONSOLA INICIALIZADA\n");
	Sock_consola=crearSocket(AF_UNIX);
	printf("CONECTANDO CON EL PPD...\n");
	system("clear");
	remote.sun_family = AF_UNIX;
	strcpy(remote.sun_path, "sock_consola");
	len = strlen(remote.sun_path) + sizeof(remote.sun_family);
	if (connect(Sock_consola, (struct sockaddr *)&remote, len) == -1) {
        perror("connect");
        exit(1);
	}	
	
	InfoIPC rInfoIPC25;
	recibirIPC(Sock_consola,&rInfoIPC25);
	printf("rInfoIPC25 %s \n",rInfoIPC25.payload);
	printf("Estableciendo algoritmo.....\n");
	if(atoi(rInfoIPC25.payload)==CLOOK){
		printf("ALGORITMO : CLOOK\n");
		ALG=CLOOK;
	}	
	if(atoi(rInfoIPC25.payload)==FSCAN){
		printf("ALGORITMO : FSCAN\n");
		ALG=FSCAN;
	}
	free(rInfoIPC25.payload);
	
	printf("Conexion establecida entre Consola y PPD\n\n"); 
	   
	printf("MENU CONSOLA PPD \n");
	printf("------------------\n");
	printf("1)trace S1 [S2 S3 S4 S5] \n");
	printf("2)info \n");
	printf("3)clean S1 S2 \n");
	printf("\n");
   
	t_commands *cmd = (t_commands *)commands_createWithConext(NULL, ' ', '\n', ' ');
	commands_add(cmd, "info", info);
	commands_add(cmd, "clean", clean);
	commands_add(cmd, "trace", trace);
	
	while (1) { 
		printf("\nIngrese comando:  ");
		fflush(stdin);
        fgets(input, 100,stdin);
		commands_parser(cmd,input);
	}
	commands_destroy(cmd);
    return 1;

}



void info(void *context, t_array *args) {
	
	InfoIPC rInfoIPC;
	rInfoIPC.payLoadLength=5;
	generarStructIPC("nada",INFO_REQUEST,&rInfoIPC);
	enviarIPC(Sock_consola,&rInfoIPC);
	free(rInfoIPC.payload);
	
	InfoIPC rInfoIPC2;
	recibirIPC(Sock_consola,&rInfoIPC2);
	printf("POSICION CABEZAL: %s\n",rInfoIPC2.payload);
	free(rInfoIPC2.payload);
	
	
}


void clean(void *context, t_array *args) {
	
	int payload;
	
	if (args == NULL || array_size(args) != 2) {
		printf("clean <sector inicial> <sector final>\n");
		return;
    }	
	
	InfoIPC rInfoIPC352;
	rInfoIPC352.payLoadLength=5;
	generarStructIPC("nada",START_CLEAN,&rInfoIPC352);
	enviarIPC(Sock_consola,&rInfoIPC352);
	free(rInfoIPC352.payload);
	
	payload=CLEAN_REQUEST;

	InfoIPC rInfoIPC353;
	rInfoIPC353.payLoadLength=strlen(array_get(args, 0))+1;
	generarStructIPC(array_get(args, 0),payload,&rInfoIPC353);
	enviarIPC(Sock_consola,&rInfoIPC353);
	free(rInfoIPC353.payload);
	
	InfoIPC rInfoIPC354;
	rInfoIPC354.payLoadLength=strlen(array_get(args, 0))+1;
	generarStructIPC(array_get(args, 1),payload,&rInfoIPC354);
	enviarIPC(Sock_consola,&rInfoIPC354);
	free(rInfoIPC354.payload);	
	
	
	
}



void trace(void *context, t_array *args) {
	
	int i;
	int payload;
	int payLoadDescriptor;
	char numero[10];
	int arrayEnvio[5];
	char tamanio[1];
	int sectores[5];
	int colaActiva[5]={-1,-1,-1,-1,-1};
	int colaPasiva[5]={-1,-1,-1,-1,-1};
	int tam;
	int posic,posic1,posic2;
	int contador;
	int pvez=1;
	
	tam=array_size(args);
	if (args == NULL || tam > 5) {
		printf("trace [lista sectores]\n");
		return;
    }
	
	
	if(ALG==CLOOK){	
	
		
		/*Envio la cantidad de sectores del trace a recibir comando*/
		payload=TAMANIO_TRACE;
		InfoIPC rInfoIPC;
		intacad(tam,tamanio);
		rInfoIPC.payLoadLength=strlen(tamanio)+1;
		generarStructIPC(tamanio,payload,&rInfoIPC);
		enviarIPC(Sock_consola,&rInfoIPC);
		free(rInfoIPC.payload);

		/*Envio aviso de que comienza tanda de sectores para trace*/
		payload=START_TRACE;
		InfoIPC rInfoIPC20;
		rInfoIPC20.payLoadLength=5;
		generarStructIPC("nada",payload,&rInfoIPC20);
		enviarIPC(Sock_consola,&rInfoIPC20);

		/*Lleno array de sectores*/
		for(i=0;i<5;i++) 
			sectores[i]=-1;
		for(i=0;i<tam;i++) 
			sectores[i]=atoi(array_get(args, i));


		/*Recibo posicion del cabezal para ordenar el array segun la misma*/
		InfoIPC rInfoIPC50;
		recibirIPC(Sock_consola,&rInfoIPC50);
		payLoadDescriptor=rInfoIPC50.payLoadDescriptor;
		
		
		ordenarArrayCLOOK(sectores,atoi(rInfoIPC50.payload));
		free(rInfoIPC50.payload);	
		
		posic=0;
		for(i=0;i<5;i++) 
			arrayEnvio[i]=-1;
		for(i=0;i<5;i++) {	
			if(sectores[i]!=-1){
				arrayEnvio[posic]=sectores[i];
				posic++;	
			}	
		}		

		/*Envio los pedidos a hilo de recibir comando por medio de los socket unix*/
		for (i=0; i < tam; i++){
					
			payload=TRACE_REQUEST;
			intacad(arrayEnvio[i],numero);
			InfoIPC rInfoIPC2;
			rInfoIPC2.payLoadLength=strlen(numero)+1;
			generarStructIPC(numero,payload,&rInfoIPC2);
			enviarIPC(Sock_consola,&rInfoIPC2);
			free(rInfoIPC2.payload);
		}
		
		payLoadDescriptor=RTA_TRACE;
		
		while(payLoadDescriptor != FIN_TRACE){
		
			/*Recibo la posicion del cabezal y la imprimo*/
			InfoIPC rInfoIPC10;
			recibirIPC(Sock_consola,&rInfoIPC10);
			payLoadDescriptor=rInfoIPC10.payLoadDescriptor;
			printf("POSICION CABEZAL: %s\n",rInfoIPC10.payload);
			free(rInfoIPC10.payload);
			
			
			/*Recibo el numero de sector y si es distinto a -1 lo imprimo*/
			InfoIPC rInfoIPC7;
			recibirIPC(Sock_consola,&rInfoIPC7);
			if(atoi(rInfoIPC7.payload)!=-1)
				printf("SECTOR SOLICITADO: %s\n",rInfoIPC7.payload);
			free(rInfoIPC7.payload);
			
			/*Recibo el trace*/
			InfoIPC rInfoIPC8;
			recibirIPC(Sock_consola,&rInfoIPC8);
			printf("SECTORES RECORRIDOS: ");
			printf("%s\n",rInfoIPC8.payload);
			free(rInfoIPC8.payload);	
			
			/*Recibo el tiempo*/
			InfoIPC rInfoIPC9;
			recibirIPC(Sock_consola,&rInfoIPC9);
			printf("TIEMPO CONSUMIDO: %s ms\n",rInfoIPC9.payload);
			free(rInfoIPC9.payload);	
		
		}
		

	}
	
	if(ALG==FSCAN){	
		
		contador=0;
		
		while(contador!=tam){
		
			if(pvez){
				posic1=0;
				/*CARGO COLA ACTIVA*/
				for(i=0;i<MAX_QUANTITY_SECTORES;i++){
					if((sectores[i]!=-1)&&(posic<TAMACTIVA)){
						colaActiva[posic]=sectores[i];
						sectores[i]=-1;
						posic1++;
					}	
				}	
				pvez=0;
			}	
			posic2=0;
			/*CARGO COLA PASIVA*/
			for(i=0;i<MAX_QUANTITY_SECTORES;i++){
				if((sectores[i]!=-1)&&(posic<TAMPASIVA)){
					colaPasiva[posic]=sectores[i];
					sectores[i]=-1;
					posic2++;
				}	
			}
			

			/*Envio la cantidad de sectores del trace a recibir comando*/
			payload=TAMANIO_TRACE;
			InfoIPC rInfoIPC;
			intacad(posic1,tamanio);
			rInfoIPC.payLoadLength=strlen(tamanio)+1;
			generarStructIPC(tamanio,payload,&rInfoIPC);
			enviarIPC(Sock_consola,&rInfoIPC);
			free(rInfoIPC.payload);

			/*Envio aviso de que comienza tanda de sectores para trace*/
			payload=START_TRACE;
			InfoIPC rInfoIPC20;
			rInfoIPC20.payLoadLength=5;
			generarStructIPC("nada",payload,&rInfoIPC20);
			enviarIPC(Sock_consola,&rInfoIPC20);

		
			/*Recibo posicion del cabezal para ordenar el array segun la misma*/
			InfoIPC rInfoIPC50;
			recibirIPC(Sock_consola,&rInfoIPC50);
			payLoadDescriptor=rInfoIPC50.payLoadDescriptor;
			
			ordenarArraySCAN(colaActiva,atoi(rInfoIPC50.payload));
			free(rInfoIPC50.payload);	
			
			/*Envio los pedidos a hilo de recibir comando por medio de los socket unix*/
			for (i=0; i < posic1; i++){
					
				payload=TRACE_REQUEST;
				intacad(colaActiva[i],numero);
				InfoIPC rInfoIPC2;
				rInfoIPC2.payLoadLength=strlen(numero)+1;
				generarStructIPC(numero,payload,&rInfoIPC2);
				enviarIPC(Sock_consola,&rInfoIPC2);
				free(rInfoIPC2.payload);
			}
			
			while(payLoadDescriptor != FIN_TRACE){
	
	
				/*Recibo la posicion del cabezal y la imprimo*/
				InfoIPC rInfoIPC10;
				recibirIPC(Sock_consola,&rInfoIPC10);
				payLoadDescriptor=rInfoIPC10.payLoadDescriptor;
				printf("POSICION CABEZAL: %s\n",rInfoIPC10.payload);
				free(rInfoIPC10.payload);
				
				
				/*Recibo el numero de sector y si es distinto a -1 lo imprimo*/
				InfoIPC rInfoIPC7;
				recibirIPC(Sock_consola,&rInfoIPC7);
				if(atoi(rInfoIPC7.payload)!=-1)
					printf("SECTOR SOLICITADO: %s\n",rInfoIPC7.payload);
				free(rInfoIPC7.payload);
				
				/*Recibo el trace*/
				InfoIPC rInfoIPC8;
				recibirIPC(Sock_consola,&rInfoIPC8);
				printf("SECTORES RECORRIDOS: ");
				printf("%s\n",rInfoIPC8.payload);
				free(rInfoIPC8.payload);	
				
				/*Recibo el tiempo*/
				InfoIPC rInfoIPC9;
				recibirIPC(Sock_consola,&rInfoIPC9);
				printf("TIEMPO CONSUMIDO: %s ms\n",rInfoIPC9.payload);
				free(rInfoIPC9.payload);	
				
				contador++;

			}
			
			if(contador!=tam){
				/*Hago el intercambio de colas*/
				for(i=0;i<MAX_QUANTITY_SECTORES;i++)
					colaActiva[i]=colaPasiva[i];
				for(i=0;i<MAX_QUANTITY_SECTORES;i++)
					colaPasiva[i]=-1;	
				posic1=posic2;
			
			}
		
		}	
			
	}		
				
}


void intacad ( int n , char* cadena)
{	
    int j=0;
    int i=0;
	char aux;

	do
    {
    cadena[i] = (n % 10) + '0';    
	n=n/10;
	i++;
	}while (n > 0);

    cadena[i] = '\0';
    i--;

	while(i>j)
	{
    aux=cadena[i];
	cadena[i]=cadena[j];
	cadena[j]=aux;
	i--;
	j++;
	}

}


int numoletra(char letra){
      
     if((isdigit(letra))||(isalpha(letra))) 
      return 0;
     
     return 1;   
}

char* Generar_Desc_ID ( void )
{
	static char ID [ 16 ] = "\0"; 
	unsigned int i;
	time_t tiempo;
	
	tiempo = time ( NULL );
	srand ((unsigned int) tiempo );
	for( i = 0 ; i < 16 ; i++ )
	{
		if((rand ( ) % 2) == 0)
		{
			ID [ i ] = 97 + rand ( ) % 25;
		}
		else
		{
			ID [ i ] = 48 + rand ( ) % 10;
		}
	}
   
	return ID;
}
